﻿/*
* See the detail code on the http://www.codeproject.com/Articles/43614/Drag-and-Drop-in-WPF
* This code descripe the drag drop more support samples such as treeview
*/

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace AppDesigner.DragDropEx
{
    
    public static class BindableDrapDrop
    {
        #region Fields

        private static DragDropInfo m_dragDropInfo = null;
        #endregion

        #region DependencyProperty

        #region DragHandlerAttachedProperty

        public static IDragSource GetDragHandler(DependencyObject obj)
        {
            return (IDragSource)obj.GetValue(DragHandlerProperty);
        }

        public static void SetDragHandler(DependencyObject obj, IDragSource value)
        {
            obj.SetValue(DragHandlerProperty, value);
        }

        public static readonly DependencyProperty DragHandlerProperty =
            DependencyProperty.RegisterAttached("DragHandler", typeof(IDragSource), typeof(BindableDrapDrop));

        #endregion

        #region DropHandlerAttachedProperty

        public static IDropTarget GetDropHandler(DependencyObject obj)
        {
            return (IDropTarget)obj.GetValue(DropHandlerProperty);
        }

        public static void SetDropHandler(DependencyObject obj, IDropTarget value)
        {
            obj.SetValue(DropHandlerProperty, value);
        }

        public static readonly DependencyProperty DropHandlerProperty =
            DependencyProperty.RegisterAttached("DropHandler", typeof(IDropTarget), typeof(BindableDrapDrop),new PropertyMetadata(null,OnDropHandlerChanged));

        private static void OnDropHandlerChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            Panel element = (Panel)sender;
            IDropTarget dropTarget = (IDropTarget)e.NewValue;
            if (dropTarget != null && element != null)
            {
                dropTarget.LayoutPanel = element;
            }
        }
        #endregion
     
        #region IsDragSourceAttachProperty

        public static bool GetIsDragSource(UIElement obj)
        {
            return (bool)obj.GetValue(IsDragSourceProperty);
        }

        public static void SetIsDragSource(UIElement obj, bool value)
        {
            obj.SetValue(IsDragSourceProperty, value);
        }

        public static readonly DependencyProperty IsDragSourceProperty =
            DependencyProperty.RegisterAttached("IsDragSource", typeof(bool), typeof(BindableDrapDrop), new PropertyMetadata(false, OnIsDragSourceChanged));

        private static void OnIsDragSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            UIElement dragSource = (UIElement)sender;
            bool isDragSource = (bool)e.NewValue;
            if (isDragSource)
            {
                dragSource.PreviewMouseLeftButtonDown += DargMouseLeftButtonDown;
                dragSource.PreviewMouseMove += DragMouseMove;
                dragSource.PreviewMouseLeftButtonUp += DragMouseLeftButtonUp;
            }
            else
            {
                dragSource.PreviewMouseLeftButtonDown -= DargMouseLeftButtonDown;
                dragSource.PreviewMouseLeftButtonUp -= DragMouseLeftButtonUp;
                dragSource.MouseMove -= DragMouseMove;
            }
        }

        static void DargMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //TODO 这个地方可能在用到滚动条的时候会有影响，应该去掉滚动条的影响
            if (m_dragDropInfo == null)
            {
                m_dragDropInfo = new DragDropInfo();
                m_dragDropInfo.SetDragInfo(sender, e);
            }
        }

        static void DragMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (m_dragDropInfo != null && GetDragHandler(m_dragDropInfo.Source) != null)
            {
                //prepare the data and effect etc...
                IDragSource dragHandler = GetDragHandler(m_dragDropInfo.Source);
                if (dragHandler != null)
                {
                    dragHandler.StartDrag(m_dragDropInfo);
                }
                else
                {
                    throw new ArgumentNullException("DragHandler is null");
                }
                if (m_dragDropInfo.DragDropData != null)
                {
                    DataObject dataObject = new DataObject(m_dragDropInfo);
                    DragDrop.DoDragDrop(m_dragDropInfo.Source, dataObject, DragDropEffects.Copy);
                }
            }
        }

        static void DragMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (m_dragDropInfo != null)
            {
                m_dragDropInfo = null;
            }
        }

        #endregion

        #region IsDropTargetAttachProperty

        public static bool GetIsDropTarget(UIElement obj)
        {
            return (bool)obj.GetValue(IsDropTargetProperty);
        }

        public static void SetIsDropTarget(UIElement obj, bool value)
        {
            obj.SetValue(IsDropTargetProperty, value);
        }

        public static readonly DependencyProperty IsDropTargetProperty =
            DependencyProperty.RegisterAttached("IsDropTarget", typeof(bool), typeof(BindableDrapDrop), new PropertyMetadata(false,OnIsDropTargetChanged));

        private static void OnIsDropTargetChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            UIElement dropTarget = (UIElement)sender;
            bool isDropTarget = (bool)e.NewValue;
            dropTarget.AllowDrop = isDropTarget;

            if (isDropTarget)
            {
                dropTarget.PreviewDragEnter += dropTarget_PreviewDragEnter;
                dropTarget.PreviewDragOver += dropTarget_PreviewDragOver;
                dropTarget.PreviewDrop += dropTarget_PreviewDrop;
                dropTarget.PreviewDragLeave += dropTarget_PreviewDragLeave;
            }
            else
            {
                dropTarget.PreviewDragEnter -= dropTarget_PreviewDragEnter;
                dropTarget.PreviewDragLeave -= dropTarget_PreviewDragLeave;
                dropTarget.PreviewDragOver -= dropTarget_PreviewDragOver;
                dropTarget.PreviewDrop -= dropTarget_PreviewDrop;
            }
        }

        static void dropTarget_PreviewDragEnter(object sender, DragEventArgs e)
        {
            dropTarget_PreviewDragOver(sender, e);
        }

        static void dropTarget_PreviewDragOver(object sender, DragEventArgs e)
        {
            e.Effects = DragDropEffects.Copy;
        }

        static void dropTarget_PreviewDrop(object sender, DragEventArgs e)
        {
            DataObject dataObject = (DataObject)e.Data;
            DragDropInfo dragDropInfo = (DragDropInfo)dataObject.GetData(typeof(DragDropInfo));
            dragDropInfo.SetDropInfo(sender, e);

            IDropTarget dropHandler = GetDropHandler((UIElement)sender);
            if (dropHandler != null)
            {
                dropHandler.Drop(dragDropInfo);
            }
            else
            {
                throw new ArgumentNullException("DropHanlder is null!");
            }
            e.Handled = true;
        }


        static void dropTarget_PreviewDragLeave(object sender, DragEventArgs e)
        {
            throw new NotImplementedException();
        }

        #endregion

        #endregion

    }
}
